home *** CD-ROM | disk | FTP | other *** search
/ Amiga Tools 3 / Amiga Tools 3.iso / grafik / raytracing / rayshade-4.0.6.3 / libray / liblight / shadow.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-09  |  7.7 KB  |  329 lines

  1. /*
  2.  * shadow.c
  3.  *
  4.  * Copyright (C) 1989, 1991, Craig E. Kolb
  5.  * All rights reserved.
  6.  *
  7.  * This software may be freely copied, modified, and redistributed
  8.  * provided that this copyright notice is preserved on all copies.
  9.  *
  10.  * You may not distribute this software, in whole or in part, as part of
  11.  * any commercial product without the express consent of the authors.
  12.  *
  13.  * There is no warranty or other guarantee of fitness of this software
  14.  * for any purpose.  It is provided solely "as is".
  15.  *
  16.  * shadow.c,v 4.1 1994/08/09 07:57:19 explorer Exp
  17.  *
  18.  * shadow.c,v
  19.  * Revision 4.1  1994/08/09  07:57:19  explorer
  20.  * Bump version to 4.1
  21.  *
  22.  * Revision 1.1.1.1  1994/08/08  04:52:04  explorer
  23.  * Initial import.  This is a prerelease of 4.0.6enh3, or 4.1 possibly.
  24.  *
  25.  * Revision 4.0.1.1  91/09/29  15:40:57  cek
  26.  * patch1: ShadowOptions was incorrectly externed.
  27.  * 
  28.  * Revision 4.0  91/07/17  14:35:34  kolb
  29.  * Initial version.
  30.  * 
  31.  */
  32. #include "libobj/geom.h"
  33. #include "libsurf/surface.h"
  34. #include "light.h"
  35.  
  36. /*
  37.  * Shadow stats.
  38.  * External functions have read access via ShadowStats().
  39.  */
  40. static unsigned long    ShadowRays, ShadowHits, CacheMisses, CacheHits;
  41. /*
  42.  * Options controlling how shadowing information is determined.
  43.  * Set by external modules via ShadowSetOptions().
  44.  */
  45. static long        ShadowOptions;
  46.  
  47. void LightCacheHit();
  48.  
  49. /*
  50.  * Trace ray from point of intersection to a light.  If an intersection
  51.  * occurs at a distance less than "dist" (the distance to the
  52.  * light source), then the point is in shadow, and TRUE is returned.
  53.  * Otherwise, the brightness/color of the light is computed ('result'),
  54.  * and FALSE is returned.
  55.  */
  56. int
  57. Shadowed(result, color, cache, ray, dist, noshadow)
  58. Color *result, *color;    /* resultant intensity, light color */
  59. ShadowCache *cache;    /* shadow cache for light */
  60. Ray *ray;        /* ray, origin on surface, dir towards light */
  61. Float dist;        /* distance from pos to light source */
  62. int noshadow;        /* If TRUE, no shadow ray is cast. */
  63. {
  64.     int i, smooth, enter;
  65.     HitList hitlist;
  66.     Ray tmpray;
  67.     ShadowCache *cp;
  68.     Vector hitpos, norm, gnorm;
  69.     Surface surf, *sptr, *prevsurf;
  70.     Float s, totaldist, statten;
  71.     Color res;
  72.  
  73.     if (noshadow || NOSHADOWS(ShadowOptions)) {
  74.         *result = *color;
  75.         return FALSE;
  76.     }
  77.  
  78.     ShadowRays++;
  79.     s = dist;
  80.     cp = &cache[ray->depth];
  81.     /*
  82.      * Check shadow cache.  SHADOWCACHE() is implied.
  83.      */
  84.     if (cp->obj) {
  85.         /*
  86.          * Transform ray to the space of the cached primitive.
  87.          */
  88.         tmpray = *ray;
  89.         if (cp->dotrans)
  90.             s *= RayTransform(&tmpray, &cp->trans);
  91.         /*
  92.          * s = distance to light source in 'primitive space'.
  93.          * Intersect ray with cached object.
  94.          */
  95.         if (cp->obj->animtrans) {
  96.             /*
  97.              * Geom has animated transformation --
  98.              * call intersect so that the transformation
  99.              * is resolved properly.
  100.              */
  101.             if (intersect(cp->obj, &tmpray, &hitlist,
  102.                 SHADOW_EPSILON, &s)) {
  103.                 CacheHits++;
  104.                 return TRUE;
  105.             }
  106.         } else if (IsAggregate(cp->obj)) {
  107.             if ((*cp->obj->methods->intersect)(cp->obj->obj,
  108.                 &tmpray, &hitlist, SHADOW_EPSILON, &s)) {
  109.                 CacheHits++;
  110.                 return TRUE;
  111.             }
  112.         } else if ((*cp->obj->methods->intersect)(cp->obj->obj,
  113.                     &tmpray, SHADOW_EPSILON, &s)) {
  114.             /* Hit cached object. */
  115.             CacheHits++;
  116.             return TRUE;
  117.         }
  118.         /*
  119.          * Did not hit anything -- zero out the cache.
  120.          */
  121.         CacheMisses++;
  122.         /*
  123.          * Transformed -- reset s for use below.
  124.          */
  125.         s = dist;
  126.         cp->obj = (Geom *)NULL;
  127.         cp->dotrans = FALSE;
  128.     }
  129.  
  130.     hitlist.nodes = 0;
  131.     if (!TraceRay(ray, &hitlist, SHADOW_EPSILON, &s)) {
  132.         /* Shadow ray didn't hit anything. */
  133.         *result = *color;
  134.         return FALSE;
  135.     }
  136.  
  137.     /*
  138.      * Otherwise, we've hit something.
  139.      */
  140.     ShadowHits++;
  141.  
  142.     /*
  143.      * If we're not worrying about transparent objects...
  144.      * This is ugly due to the fact that we have to find
  145.      * the surface associated with the object that was hit.
  146.      * GetShadingSurf() will always return a non-null value.
  147.      *
  148.      * ***NOTE**
  149.      * The transparency of the surface is checked below without
  150.      * applying textures, if any, to it.  This means that if
  151.      * an object may be made trasparent by a texture, its
  152.      * surface should have non-zero transparency *before* texturing
  153.      * as well.
  154.      */
  155.     if (!SHADOWTRANSP(ShadowOptions)) {
  156.         if (SHADOWCACHE(ShadowOptions))
  157.             LightCacheHit(&hitlist, cp);
  158.         return TRUE;
  159.     }
  160.  
  161.     /*
  162.      * We've hit a transparent object.  Attenuate the color of the light
  163.      * source and continue the ray until we hit background or a
  164.      * non-transparent object.  Note that this is incorrect if DefIndex or
  165.      * any of the indices of refraction of the surfaces differ.
  166.      */
  167.  
  168.     totaldist = 0.;
  169.     prevsurf = (Surface *)NULL;
  170.     res = *color;
  171.  
  172.     do {
  173.         /*
  174.          * Get a pointer to the surface to be used
  175.          * for shading...
  176.          */
  177.         sptr = GetShadingSurf(&hitlist);
  178.         if (sptr->transp < EPSILON) {
  179.             if (SHADOWCACHE(ShadowOptions))
  180.                 LightCacheHit(&hitlist, cp);
  181.             return TRUE;
  182.         }
  183.         /*
  184.          * Take specular transmission attenuation from
  185.          * previous intersection into account.
  186.          */
  187.         if (prevsurf) {
  188.             if (prevsurf->statten != 1.) {
  189.                 statten = pow(prevsurf->statten, s - totaldist);
  190.                 ColorScale(statten, res, &res);
  191.             }
  192.         }
  193.         /*
  194.          * Perform texturing and the like in case surface
  195.          * transparency is modulated.
  196.          */
  197.         /* copy the surface to be used... */
  198.         surf = *sptr;
  199.         enter = ComputeSurfProps(&hitlist, ray, &hitpos,
  200.             &norm, &gnorm, &surf, &smooth);
  201.         if (enter)
  202.             prevsurf = &surf;
  203.         else
  204.             prevsurf = (Surface *)NULL;
  205.         /*
  206.          * Attenuate light source by body color of surface.
  207.          */
  208.         ColorScale(surf.transp, res, &res);
  209.         ColorMultiply(res, surf.body, &res);
  210.         /*
  211.          * Return if attenuation becomes large.
  212.          * In this case, the light was attenuated to nothing,
  213.          * so we can't cache anything...
  214.          */
  215.         if (res.r < EPSILON && res.g < EPSILON && res.b < EPSILON)
  216.             return TRUE;
  217.         /*
  218.          * Min distance is previous max.
  219.          */
  220.         totaldist = s + EPSILON;
  221.         /*
  222.          * Max distance is dist to light source
  223.          */
  224.         s = dist;
  225.         /*
  226.          * Trace ray starting at new origin and in the
  227.          * same direction.
  228.          */
  229.         hitlist.nodes = 0;
  230.     } while (TraceRay(ray, &hitlist, totaldist, &s));
  231.     if (prevsurf) {
  232.         if (prevsurf->statten != 1.) {
  233.             statten = pow(prevsurf->statten, dist - totaldist);
  234.             ColorScale(statten, res, &res);
  235.         }
  236.     }
  237.  
  238.     *result = res;
  239.     return FALSE;
  240. }
  241.  
  242. void
  243. ShadowStats(shadowrays, shadowhit, cachehit, cachemiss)
  244. unsigned long *shadowrays, *shadowhit, *cachehit, *cachemiss;
  245. {
  246.     *shadowrays = ShadowRays;
  247.     *shadowhit = ShadowHits;
  248.     *cachehit = CacheHits;
  249.     *cachemiss = CacheMisses;
  250. }
  251.  
  252. void
  253. ShadowSetOptions(options)
  254. long options;
  255. {
  256.     ShadowOptions = options;
  257. }
  258.  
  259. void
  260. LightCacheHit(hitlist, cache)
  261. HitList *hitlist;
  262. ShadowCache *cache;
  263. {
  264.     HitNode *np;
  265.     int i, n;
  266.     extern long ShadowOptions;
  267.  
  268.     i = 0;
  269.  
  270.     if (SHADOWCSG(ShadowOptions)) {
  271.         /*
  272.          * There's possibly a CSG object in the
  273.          * hitlist, so we can't simply cache the
  274.          * primitive that was hit.  Find the
  275.          * object lowest in hit that's not part
  276.          * of a CSG object, and cache it.
  277.          */
  278.         i = FirstCSGGeom(hitlist);
  279.     }
  280.  
  281.     if (SHADOWBLUR(ShadowOptions)) {
  282.         /*
  283.          * Something might be animated --
  284.          * gotta cache the puppy.
  285.          */
  286.         n = FirstAnimatedGeom(hitlist);
  287.         if (n > i)
  288.             i = n;
  289.     }
  290.  
  291.     /*
  292.      * Compute total world-->cached object
  293.      * transformation and store in cache->trans.
  294.      */
  295.     /*
  296.      * Find the first transformation...
  297.      */
  298.     np = &hitlist->data[i];
  299.     cache->obj = np->obj;
  300.     /*
  301.      * If the cached object is animated, then we don't
  302.      * want to include the object's transformation(s)
  303.      * in cache->trans (it's taken care of in shadowed()
  304.      * by calling intersect).
  305.      */
  306.     if (cache->obj->animtrans) {
  307.         i++;
  308.         np++;
  309.     }
  310.     cache->dotrans = FALSE;
  311.     while (i < hitlist->nodes -1) {
  312.         if (np->obj->trans) {
  313.             if (cache->dotrans) {
  314.                 MatrixMult(
  315.                     &np->obj->trans->itrans,
  316.                     &cache->trans,
  317.                     &cache->trans);
  318.             } else {
  319.                 MatrixCopy(
  320.                     &np->obj->trans->itrans,
  321.                     &cache->trans);
  322.                 cache->dotrans = TRUE;
  323.             }
  324.         }
  325.         i++;
  326.         np++;
  327.     }
  328. }
  329.